/******************************************************************************
 * @file     vcom_serial.c
 * @brief    NANO100 series USBD driver Sample file
 * @version  2.0.0
 * @date     17, Dec, 2014
 *
 * @note
 * Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
 ******************************************************************************/

/*!<Includes */
#include <string.h>
#include <stdio.h>
#include "Nano100Series.h"
#include "common.h"
#include "proximity_sensor.h"
#include "audio.h"

/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/
#define WM8960_DEVICE_ADDR      (0x34>>1)
#define ALC5640_DEVICE_ADDR     (0x38>>1)

struct rt5640_init_reg {
	uint8_t reg;
	uint16_t val;
};

static struct rt5640_init_reg init_list[] = {
//	{RT5640_GEN_CTRL1	, 0x3f01},//fa[12:13] = 1'b; fa[8~11]=1; fa[0]=1
	{RT5640_ADDA_CLK1	, 0x1114},//73[2] = 1'b
//	{RT5640_MICBIAS		, 0x3030},//93[5:4] = 11'b
	{RT5640_CLS_D_OUT	, 0xa000},//8d[11] = 0'b
	{RT5640_CLS_D_OVCD	, 0x0334},//8c[8] = 1'b
	//{RT5640_PRIV_INDEX	, 0x001d},//PR1d[8] = 1'b;
//	{RT5640_PRIV_DATA	, 0x0347},
//	{RT5640_PRIV_INDEX	, 0x003d},//PR3d[12] = 0'b; PR3d[9] = 1'b
//	{RT5640_PRIV_DATA	, 0x2600},
//	{RT5640_PRIV_INDEX	, 0x0012},//PR12 = 0aa8'h
//	{RT5640_PRIV_DATA	, 0x0aa8},
//	{RT5640_PRIV_INDEX	, 0x0014},//PR14 = 8aaa'h
//	{RT5640_PRIV_DATA	, 0x8aaa},
//	{RT5640_PRIV_INDEX	, 0x0020},//PR20 = 6115'h
//	{RT5640_PRIV_DATA	, 0x6115},
//	{RT5640_PRIV_INDEX	, 0x0023},//PR23 = 0804'h
//	{RT5640_PRIV_DATA	, 0x0804},
	/*playback*/
	{RT5640_STO_DAC_MIXER	, 0x1414},//Dig inf 1 -> Sto DAC mixer -> DACL
	{RT5640_OUT_L3_MIXER	, 0x01fe},//DACL1 -> OUTMIXL
	{RT5640_OUT_R3_MIXER	, 0x01fe},//DACR1 -> OUTMIXR
	{RT5640_HP_VOL		, 0x8888},//OUTMIX -> HPVOL
	{RT5640_HPO_MIXER	, 0xc000},//HPVOL -> HPOLMIX
//	{RT5640_HPO_MIXER	, 0xa000},//DAC1 -> HPOLMIX
//	{RT5640_CHARGE_PUMP	, 0x0f00},
	{RT5640_PRIV_INDEX	, 0x0090},
	{RT5640_PRIV_DATA	, 0x2000},
	{RT5640_PRIV_INDEX	, 0x0091},
	{RT5640_PRIV_DATA	, 0x1000},
//	{RT5640_HP_CALIB_AMP_DET, 0x0420},
	{RT5640_SPK_L_MIXER	, 0x0036},//DACL1 -> SPKMIXL
	{RT5640_SPK_R_MIXER	, 0x0036},//DACR1 -> SPKMIXR
	{RT5640_SPK_VOL		, 0x8888},//SPKMIX -> SPKVOL
	{RT5640_SPO_CLSD_RATIO	, 0x0001},
	{RT5640_SPO_L_MIXER	, 0xe800},//SPKVOLL -> SPOLMIX
	{RT5640_SPO_R_MIXER	, 0x2800},//SPKVOLR -> SPORMIX
//	{RT5640_SPO_L_MIXER	, 0xb800},//DAC -> SPOLMIX
//	{RT5640_SPO_R_MIXER	, 0x1800},//DAC -> SPORMIX  
//	{RT5640_I2S1_SDP	, 0xD000},//change IIS1 and IIS2
	/*record*/
	{RT5640_IN1_IN2		, 0x5080},//IN1 boost 40db and differential mode
	{RT5640_IN3_IN4		, 0x0500},//IN2 boost 40db and signal ended mode
	{RT5640_REC_L2_MIXER	, 0x007d},//Mic1 -> RECMIXL
	{RT5640_REC_R2_MIXER	, 0x007d},//Mic1 -> RECMIXR
//	{RT5640_REC_L2_MIXER	, 0x006f},//Mic2 -> RECMIXL
//	{RT5640_REC_R2_MIXER	, 0x006f},//Mic2 -> RECMIXR
	{RT5640_STO_ADC_MIXER	, 0x3020},//ADC -> Sto ADC mixer
	
	{RT5640_JD_CTRL	,      0x2bc0},//GPIO/IRQ    0x2bc0 low=hp high=spk     0x2e80 low=spk high=hp

};


void audio_init(){
	//WM8960 init
/*
  I2c1_write(8, WM8960_DEVICE_ADDR, 0xf<<1, 0,0);
	delay(50); 
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x19<<1|1, 0xf0,0);
	delay(50); 
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x34<<1, 0x0,0);
	//I2c1_write(8, WM8960_DEVICE_ADDR, 0x35<<1, 0x86,0);
	//I2c1_write(8, WM8960_DEVICE_ADDR, 0x36<<1, 0xc2,0);
	//I2c1_write(8, WM8960_DEVICE_ADDR, 0x37<<1, 0x26,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x04<<1, 0x00,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x08<<1 | 1, 0xc7,0);//0xc4
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x07<<1, 0x02,0);//0x42
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x1a<<1|1, 0xf8,0);//0xfb

	delay(50); 
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x2f<<1, 0x0c,0);//0x3C
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x00<<1|1, 0x0,0);//0x3f
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x01<<1|1, 0x0,0);//0x3f
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x02<<1|1, 0x6F,0);//0x7f
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x03<<1|1, 0x6F,0); //0x7f
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x05<<1, 2,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x09<<1, 0x40,0);
	
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x0a<<1, 0xff,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x0b<<1, 0xff,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x12<<1, 0x0,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x15<<1, 0xc3,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x16<<1, 0xc3,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x1c<<1, 0x9D,0); //0C
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x20<<1, 0x0,0); // 0x108
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x21<<1, 0x0,0);//0x108
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x22<<1|1, 0x0,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x25<<1|1, 0x0,0);
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x28<<1|1, 0x74,0);//0x79
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x29<<1|1, 0x74,0);//0x79
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x30<<1, 0x3,0);
	//I2c1_write(8, WM8960_DEVICE_ADDR, 0x31<<1, 0x37,0);//headphone
	//I2c1_write(8, WM8960_DEVICE_ADDR, 0x17<<1|1, 0xC1,0);//headphone
	//I2c1_write(8, WM8960_DEVICE_ADDR, 0x18<<1, 0x20,0);//headphone
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x31<<1, 0xf7,0); ////0xf7      
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x33<<1, 0x84,0);
	
	
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x18<<1, 0x60,0);//headphone  0x40 
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x1b<<1, 0x40,0);//headphone
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x17<<1|1, 0xC3,0);//headphone
	I2c1_write(8, WM8960_DEVICE_ADDR, 0x1d<<1, 0x30,0);//headphone
	
	*/
	

	//ALC5640
	//                                  reg   dat1  dat2
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x00, 0x00,0x01);
	delay(50); 
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x01, 0x05,0x05);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x02, 0x0f,0x0f);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x8C,0x03,0x28);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x8D, 0x18,0x00);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x45, 0xC0,0x00);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x46, 0x00,0x3c);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x47, 0x00,0x3c);
	
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x4f, 0x01,0xfe);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x52, 0x01,0xfe);
	
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x48, 0xe8,0x00);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x49, 0x28,0x00);
	
	
	
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x70, 0x80,0x08);
	
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x73, 0x80,0x15);
	
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x2A, 0x14,0x14);
	//I2c1_write(16, ALC5640_DEVICE_ADDR, 0x2F, 0x40,0x00);
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0xFA, 0x34,0x01);
	
	
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x74, 0x5C,0x00);

	
	I2c1_write(16, ALC5640_DEVICE_ADDR, RT5640_PRIV_INDEX, 0x00,0x3D);
	I2c1_write(16, ALC5640_DEVICE_ADDR, RT5640_PRIV_DATA, 0x26,0x00);
		//power
//	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x61, 0x98,0x01);//0x9801
//	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x62, 0xE0,0x00);//test
//	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x63, 0xFD,0xFC);//test
//	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x64, 0xA,0x00);//test
//	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x65, 0xF0,0x00);//0xf000
//	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x66, 0xFF,0x00);//0xcC00
			I2c1_write(16, ALC5640_DEVICE_ADDR, 0x61, 0x98,0x01);//0x9801
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x62, 0xE0,0x00);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x63, 0xFD,0xFC);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x64, 0xA,0x00);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x65, 0xF0,0x00);//0xf000
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x66, 0xFF,0x00);//0xcC00
		
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x8e, 0x00,0x9D);//0xc000
		I2c1_write(16, ALC5640_DEVICE_ADDR, 0x8f, 0x1,0x40);//0xc000
	I2c1_write(16, ALC5640_DEVICE_ADDR, 0xBB, 0x2e,0x80);//0xc000
	
}


void alc5640_pwr_state(int state){
   if(state){
		   	I2c1_write(16, ALC5640_DEVICE_ADDR, 0x61, 0x98,0x01);//0x9801
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x62, 0xE0,0x00);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x63, 0xFD,0xFC);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x64, 0xA,0x00);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x65, 0xF0,0x00);//0xf000
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x66, 0xFF,0x00);//0xcC00
	 }
	 else{
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x61, 0,0);//0x9801
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x62, 0,0);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x63, 0,0);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x64, 0,0);//test
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x65, 0,0);//0xf000
	      I2c1_write(16, ALC5640_DEVICE_ADDR, 0x66, 0,0);//0xcC00
	 }
}

void wm8960_pwr_state(int state){
    if(state){
			 
		   I2c1_write(8, WM8960_DEVICE_ADDR, 0x1a<<1|1, 0xf8,0);//0xfb
	
		}
		else
		{

		   I2c1_write(8, WM8960_DEVICE_ADDR, 0x1a<<1, 0x0,0);//0xfb
		}
}

void PWM0_IRQHandler(void);
void PWM0_IRQHandler(void){
  PWM_EnableOutput(PWM1,PWM_CH_2_MASK);
	PWM_ClearPeriodIntFlag(PWM1,2);
}

void ADC_IRQHandler(void)
{
    uint32_t u32Flag;
     float pwm_speed;
    // Get ADC conversion finish interrupt flag
    u32Flag = ADC_GET_INT_FLAG(ADC, ADC_ADF_INT);
 
    if(u32Flag & ADC_ADF_INT){
		   uint32_t adc_val;
			adc_val = ADC_GET_CONVERSION_DATA(ADC, 0);
			pwm_speed = (float)adc_val / 4095 * 100;
			info("ADC val = %u  %d\n",adc_val,(int)pwm_speed);
			PWM_ConfigOutputChannel(PWM0,1,250,(int)pwm_speed);
			PWM_Start(PWM0,PWM_CH_1_MASK);
		}
     
    ADC_CLR_INT_FLAG(ADC, u32Flag);
		ADC_DisableInt(ADC, ADC_ADF_INT);
}


void motor_init(){
  GPIO_SetMode(PC, BIT14, GPIO_PMD_OUTPUT); //M-
	//GPIO_SetMode(PC, BIT15, GPIO_PMD_OUTPUT);//M+
	GPIO_SetMode(PB, BIT15, GPIO_PMD_OUTPUT);
	PC14 = 0;
	//PC15 = 1;
	PB15 = 1;
	PWM_ConfigOutputChannel(PWM0,1,250,99);
	PWM_EnableOutput(PWM0,PWM_CH_1_MASK);
	//PWM_EnablePeriodInt(PWM1,1,)
	PWM_Start(PWM0,PWM_CH_1_MASK);
	
	ADC_Open(ADC, ADC_INPUT_MODE_SINGLE_END, ADC_OPERATION_MODE_SINGLE_CYCLE, ADC_CH_0_MASK);
	ADC_SET_REF_VOLTAGE(ADC, ADC_REFSEL_POWER);

    // Power on ADC
    ADC_POWER_ON(ADC);

    // Set Verf to AVDD
    ADC_SET_REF_VOLTAGE(ADC,ADC_REFSEL_VREF);

    // Enable ADC ADC_IF interrupt
    ADC_EnableInt(ADC, ADC_ADF_INT);
    NVIC_EnableIRQ(ADC_IRQn);
		ADC_START_CONV(ADC);
}

void update_motor_speed(){
  ADC_EnableInt(ADC, ADC_ADF_INT);
	ADC_START_CONV(ADC);
}